<?php
/** 
 * @package AMFramework
 * @subpackage Core
 * @author Marcu Alexandru
 * @version 1.0 $Build 305b  
 */
defined('_INDEX') or die('Restricted');

class Amfw_Session extends Amfw_Object {
	protected $_sessId;
	protected $_sessName;
	protected $_cache;
	
	protected $_started = false;
	//protected $_validated = false;
	
	protected $userInfo = array();
	private $token;
	private static $_sessionInst = null;
	
	
	public function start($sess_name = 'fwsess', $cache = 'nocache') 
	{
		session_cache_limiter($cache);
		session_name($sess_name);
		session_start();
		
		$started = $this->getVar($sess_name.'.started');
		// If there's no session we'll regenerate and remove the old sess
		if($started !== true) {
			session_regenerate_id(true);
			$this->userInfo['ip'] = md5( $sess_name . '@' . $_SERVER['REMOTE_ADDR'] );
			$this->userInfo['user_agent'] = md5( $sess_name . '@' . $_SERVER['HTTP_USER_AGENT']);
			$this->_setv($sess_name.'.config', $this->userInfo);
			$this->_setv($sess_name.'.started', true); //Setam configul si pornim sesiunea
		}
		// Punem in obiect info de la client si le validam cu cele din sesiune
		$this->userInfo['ip'] = md5( $sess_name.'@'.$_SERVER['REMOTE_ADDR']);
		$this->userInfo['user_agent'] = md5($sess_name.'@'.$_SERVER['HTTP_USER_AGENT']);
		
		// Sesiunea e pornita mai trebuie doar sa o validam;
		$config = $this->getVar($sess_name.'.config');
		if(!is_array($config) || empty($config)){ // Avem probleme
			trigger_error('Session/start --> Invalid session',E_USER_ERROR);
		} elseif(is_array($config) && !empty($config)) {
			foreach($config as $key => $value) {
				if($config[$key] !== $this->userInfo[$key]) // Din nou probleme
					trigger_error('Session/start/foreach(din nou probleme)',E_USER_ERROR);
			}
		}
		// Urcam in obiect celelalte informatii pentru a putea fi reutilizate
		$this->_started = true;
		$this->_sessName = $sess_name;
		$this->_sessId = session_id();

		//Tokenul este creat si este pus is sesiune
		$token = $this->_createToken();
		$this->_setv($sess_name.'.token',$token);
	}
	
	function validate() {
			// Sesiunea e pornita mai trebuie doar sa o validam;
		$config = $this->getVar($this->_sessName.'.config');
		if(!is_array($config) || empty($config)){ // Avem probleme
			trigger_error('Session/start --> Invalid session',E_USER_ERROR);
		} elseif(is_array($config) && !empty($config)) {
			foreach($config as $key => $value) {
				if($config[$key] !== $this->userInfo[$key]) // Din nou probleme
					trigger_error('Session/start/foreach(din nou probleme)',E_USER_ERROR);
			}
		}
	}
	
	function _createToken() {
		// O serie de informatii de baza convertite in MD5,
		// apoi in base64, si apoi alipite, vor face `tokenul`
		// pentru protectia formularelor de atacuri Csrf
		$hashes = array();
		$hashes[] = $this->userInfo['ip'];
		$hashes[] = $this->userInfo['user_agent'];
		$hashes[] = Amfw_Utils::md5fromArray(array($this->_sessName,$this->_sessId));
		$token = base64_encode(implode('',$hashes));

		return $token;
	}
	
	function getToken() {
		//return $this->token;
		return $this->_getv($this->_sessName.".token");
	}
	
/*	public function &getInstance( ) {
		 if (!is_null(self::_sessionInst)){ return self::_sessionInst; }
		 else { trigger_error('session Instance doesn\'t exist',E_USER_WARNING);
		 		return null; }
	}*/
	
	public function isSetVar( $name ) {
		$expr = "return isset(".self::_getvarExpr($name).");";
		return eval($expr);
	}
	
	public function setVar($name,$value){ //functie publica, totul se creeaza in namespaceul 
											// implicit (fwsess / orice alt nume)
		if(strpos($name,$this->_sessName.".") !== false ) {
			//trigger_error('use _setv if you wish to define your sess var in another namespace',E_USER_NOTICE);
			$this->_setv($name,$value);
			return 0;//DEFINED NAMESPACE
		}
		$name = $this->_sessName.'.'.$name;	// daca nu este setat namespaceul il folosim pe cel implicit
		$this->_setv($name,$value);
		return 1;//DEFAULT NAMESPACE
	}
		
	
	public function _setv($name, $value) { //setter care citeste namespaceul (numele sesiunii)
		$expr = $this->_getvarExpr($name). "=\$value;";
		eval($expr);
	}
	
	//TODO: E dubios mai jos si la setVar cu denumirea sesiunii la inceput
	function getVar($name,$default=0,$mask=0) {
		if(strpos($name,$this->_sessName.".") === false)
			$var = $this->_getv($this->_sessName.".$name");//DEFAULT NAMESPACE
		else $var = $this->_getv($name);//DEFINED NAMESPACE

		if(is_null($var)) { return null; }
		if(is_bool($var) || is_numeric($var)) { return $var; }
		else {
			static $filter;
			if(!isset($filter)) { $filter = Amfw_InputFilter::getInstance(); }
			//filtram variabila in functie de ce flaguri avem(la fel ca in amfw_request)
			switch($mask){
				case 2: break; // Allow raw
				case 4: $filter->init(null,null,1,1); //Safe html
						$var=$filter->process($var);
						break;
				default: $filter->init(); //Filtru implicit
						$var=$filter->process($var);
						break;
			}
			if($mask != 1) { Amfw_Utils::trim($var); } // Trim by reference;
			return $var;
		}
		trigger_error('SESSION::shouldnt have gotten here(GETVAR)',E_USER_ERROR);
	}
	
	function _getvarExpr($name) {
		//Intoarce dintr-un nume gen: foo.oof , numele variabilei : $_SESSION['foo']['oof']
		$expr = "\$_SESSION";
		if(strpos($name,'.') !== false) {
			$tokens = explode('.', $name);
			foreach($tokens as &$token) { $expr .= "['$token']"; }
		} else $expr .= "['$name']";
		return $expr;
	}

	function _getv($name) {
		if(!self::isSetVar($name)) { return null; }
		$expr = "return ".$this->_getvarExpr($name).";";
		return eval($expr);
	}
	public static function restart() {
		session_unset();
		session_destroy();

		//Now that we've destroyed it all, we'll create the $_SESSION again
		$session =& Amfw_Factory::getSession();
		$session->start();
	}
}